liwe.events = {};

if ( document.addEventListener )
{
	// W3C DOM 2 Events model
	liwe.events.add 	= function ( target, type, listener ) { 
		if ( ! target || ! listener ) return;

		target.addEventListener ( type, listener, false ); return target; 
	};
	liwe.events.del 	= function ( target, type, listener ) { target.removeEventListener ( type, listener, false ); };
	liwe.events.prevent 	= function ( e ) { e.preventDefault (); };
	liwe.events.stop 	= function ( e ) { e.stopPropagation(); };

	liwe.events.source  	= function ( e ) { return e.target; };
	liwe.events.keycode 	= function ( e ) { return e.which; };
} else if ( document.attachEvent ) {
	// Internet Explorer Events model
	liwe.events._add		= function ( target, type, listener )
	{
		target.attachEvent ( "on" + type, listener );
	};
	liwe.events.add		= function ( target, type, listener )
	{
		if  ( ! target || ! listener ) return;

		// prevent adding the same listener twice, since DOM 2 Events ignores
		// duplicates like this
		if ( liwe.events._find ( target, type, listener) != -1 ) return null;

		// _cback calls listener as a method of target in one of two ways,
		// depending on what this version of IE supports, and passes it the global
		// event object as an argument
		var _cback = function ()
		{
			var e = window.event;

			if ( Function.prototype.call )
				listener.call ( target, e );
			else {
				target._curr_listener = listener;
				target._curr_listener ( e )
				target._curr_listener = null;
			}
		};

    		// add _cback using IE's attachEvent method
    		target.attachEvent ( "on" + type, _cback );

    		// create an object describing this listener so we can clean it up later
    		var rec =
    		{
      			target: target,
      			type: type,
      			listener: listener,
      			_cback: _cback
    		};

		// get a reference to the window object containing target
		//var targetDocument = target.document || target;
		//var targetWindow = targetDocument.parentWindow;
		var targetWindow = target.ownerDocument ? target.ownerDocument.parentWindow : window;

		// create a unique ID for this listener
		var listenerId = "l" + liwe.events._list_counter++;

		// store a record of this listener in the window object
		if ( !targetWindow._all ) targetWindow._all = {};
		targetWindow._all [ listenerId ] = rec;

		// store this listener's ID in target
		if ( ! target._listeners ) target._listeners = [];
		target._listeners [ target._listeners.length ] = listenerId;

		if ( ! targetWindow._unload_added )
		{
			targetWindow._unload_added = true;
			targetWindow.attachEvent ( "onunload", liwe.events._del_all );
		}

		return target;
  	};

  
	liwe.events.del = function ( target, type, listener )
	{
		// find out if the listener was actually added to target
		var listenerIndex = liwe.events._find ( target, type, listener );
		if ( listenerIndex == -1 ) return;

		// get a reference to the window object containing target
		var targetDocument = target.document || target;
		var targetWindow   = targetDocument.parentWindow;

		// obtain the record of the listener from the window object
		var listenerId = target._listeners [ listenerIndex ];
		var rec = targetWindow._all [ listenerId ];

		// remove the listener, and remove its ID from target
		target.detachEvent ( "on" + type, rec._cback );
		target._listeners.splice ( listenerIndex, 1 );

		// remove the record of the listener from the window object
		delete targetWindow._all [ listenerId ];
	};

	liwe.events.prevent = function ( e ) { e.returnValue = false; };
	liwe.events.stop = function ( e ) { e.cancelBubble = true; };
	liwe.events.source   = function ( e ) { return event.srcElement; };
	liwe.events.keycode  = function ( e ) { return event.keyCode; };

	liwe.events._find = function ( target, type, listener )
	{
		// get the array of listener IDs added to target
		var listeners = target._listeners;
		if ( !listeners ) return -1;

		// get a reference to the window object containing target
		var targetDocument = target.document || target;
		var targetWindow   = targetDocument.parentWindow;

		// searching backward ( to speed up onunload processing ), find the listener
		for ( var i = listeners.length - 1; i >= 0; i-- )
		{
			// get the listener's ID from target
			var listenerId = listeners [ i ];

			// get the record of the listener from the window object
			var rec = targetWindow._all [ listenerId ];

			// compare type and listener with the retrieved record
			if (rec.type == type && rec.listener == listener) return i;
		}

		return -1;
	};

	liwe.events._del_all = function()
	{
		var targetWindow = this, id;

		for ( id in targetWindow._all )
		{
			var rec = targetWindow._all [ id ];
			if ( typeof ( rec ) == "function" ) continue;

			rec.target.detachEvent ( "on" + rec.type, rec._cback );
			delete targetWindow._all[id];
		}
	};

  	liwe.events._list_counter = 0;
}


function $e ( id, event_name, func )
{
	var target = $el ( id );

	return liwe.events.add ( target, event_name, func );
}

liwe.events.once = function ( target, event_name, cback ) 
{
	var wrap = function ( e ) 
	{
		cback ( e );
		liwe.events.del ( target, event_name, wrap );
	};

	liwe.events.add ( target, event_name, wrap );
};

/*
EXAMPLES

liwe.events.add ( window, 'load', on_load, false );
*/
